package com.gitee.fastmybatis.core.mapper;

import com.gitee.fastmybatis.core.query.LambdaQuery;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.fastmybatis.core.support.Getter;
import com.gitee.fastmybatis.core.util.ClassUtil;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Lambda查询
 *
 * @author 六如
 */
public interface LambdaSearchMapper<E> extends SearchMapper<E> {

    /**
     * 创建一个LambdaUpdateQuery
     *
     * @return 返回LambdaUpdateQuery
     */
    default LambdaQuery<E> query() {
        return Query.create(getEntityClass());
    }

    /**
     * 根据字段查询一条记录 (末尾加 limit 1)<br>
     * 如果要判断多条，参考 {@link #getOneByField }
     * <pre>
     * {@literal
     * TUser user = mapper.get(TUser::getUsername, "王五");
     * }
     * </pre>
     * <code>
     * SELECT col1,col2,... FROM table WHERE {column} = {value} LIMIT 1
     * </code>
     *
     * @param column 数据库字段名
     * @param value  字段值
     * @return 返回实体对象，没有返回null
     * @see #getOneByField(String, Object)
     */
    default E getByField(Getter<E, ?> column, Object value) {
        String columnName = ClassUtil.getColumnName(column);
        return getByField(columnName, value);
    }

    /**
     * 根据字段查询一条记录, 返回OneResult<br>
     * <pre>
     * {@literal
     * OneResult user = mapper.getOneByField(TUser::getUsername, "王五");
     * }
     * </pre>
     * <code>
     * SELECT col1,col2,... FROM table WHERE {column} = {value} LIMIT 1
     * </code>
     *
     * @param column 数据库字段名
     * @param value  字段值
     * @return 返回实OneResult
     */
    default OneResult<E> getOneByField(Getter<E, ?> column, Object value) {
        String columnName = ClassUtil.getColumnName(column);
        return getOneByField(columnName, value);
    }

    /**
     * 查询全部数据,指定返回字段
     * <pre>
     * {@literal
     * List<TUser> users = mapper.listAll(TUser::getId, TUser::getUsername);
     *
     * 对应SQL:SELECT id, username FROM t_user;
     * }
     * </pre>
     *
     * @param columns 指定返回字段
     * @return 返回全部数据，没有返回空list
     */
    default List<E> listAll(Getter<E, ?>... columns) {
        LambdaQuery<E> query = Query.create(getEntityClass())
                .select(columns);
        return list(query);
    }

    /**
     * 根据字段查询所有记录<br>
     *
     * <pre>
     * {@literal
     * List<TUser> list = mapper.listByField(TUser::getAge, 20);
     * }
     * </pre>
     * 对应SQL:
     * <code>
     * SELECT col1, col2, ... FROM t_user WHERE age = 20;
     * </code>
     *
     * @param column 字段
     * @param value  字段值,可以是单值也可以是集合，Number/String/Boolean/Collection/Array
     * @return 返回实体对象集合，没有返回空集合
     */
    default List<E> listByField(Getter<E, ?> column, Object value) {
        return listByField(ClassUtil.getColumnName(column), value);
    }

    /**
     * 根据某个字段检查记录是否存在
     * <pre>
     * boolean b = mapper.checkExist(TUser::getUsername, "jim");
     * </pre>
     *
     * @param getter 字段
     * @param value  值
     * @return 返回true，记录存在
     */
    default boolean checkExist(Getter<E, ?> getter, Object value) {
        return checkExist(ClassUtil.getColumnName(getter), value);
    }

    /**
     * 根据某个字段检查记录是否存在，且不是指定id的那条记录
     * <pre>
     * boolean b = mapper.checkExist(TUser:getUsername, "jim", 1)
     *
     * SELECT username FROM table WHERE username = ? and id != ?
     * </pre>
     *
     * @param getter 数据库字段名
     * @param value  值
     * @param id     需要排除的id值
     * @return 返回true，记录存在
     */
    default boolean checkExist(Getter<E, ?> getter, Object value, Serializable id) {
        return checkExist(ClassUtil.getColumnName(getter), value, id);
    }

    /**
     * 查询结果并分组
     * <pre>
     * {@literal
     * Map<Long, List<SysDictValueBO>> map = service.getMapGrouping(query, SysDictValue::getItemId, sysDictValue -> {
     *             return CopyUtil.copyBean(sysDictValue, SysDictValueBO::new);
     *         });
     * }
     * </pre>
     *
     * @param query       查询条件
     * @param keyGetter   分组key
     * @param valueGetter 值转换
     * @param <K>         key类型
     * @param <V>         value类型
     * @return 返回map
     */
    default <K, V> Map<K, List<V>> getMapGrouping(Query query, Function<E, K> keyGetter, Function<E, V> valueGetter) {
        return this.list(query)
                .stream()
                .collect(
                        Collectors.groupingBy(
                                keyGetter,
                                LinkedHashMap::new,
                                Collectors.mapping(valueGetter, Collectors.toList())
                        )
                );
    }

    /**
     * 查询结果并分组
     * <pre>
     * {@literal
     * Map<Long, List<SysDictValue>> map = service.getMapGrouping(this.query().eq(TUser::getId, 1), SysDictValue::getItemId);
     * }
     * </pre>
     *
     * @param query     查询条件
     * @param keyGetter 分组key
     * @param <K>       key类型
     * @return 返回map
     */
    default <K> Map<K, List<E>> getMapGrouping(Query query, Function<E, K> keyGetter) {
        return getMapGrouping(query, keyGetter, Function.identity());
    }


}
